package com.shoulder.log.autoconfigure;

import com.shoulder.imports.Imports;
import com.shoulder.log.aop.LogAop;
import com.shoulder.log.enums.LogPrinterEnum;
import com.shoulder.log.event.LogEventListener;
import com.shoulder.log.mdc.MdcTaskExecutor;
import com.shoulder.log.printer.LogPrinter;
import com.shoulder.log.properties.LogProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;

import java.util.concurrent.ThreadPoolExecutor;

@Imports(value = AutoConfiguration.class)
@AutoConfiguration
@EnableConfigurationProperties(LogProperties.class)
public class LogAutoConfiguration {
    //最大可用的CPU核数
    public static final int PROCESSORS = Runtime.getRuntime().availableProcessors();

    /**
     * 线程池定义，使用mdc解决异步中无链路id的问题
     */
    @Bean
    public MdcTaskExecutor mdcTaskExecutor() {
        MdcTaskExecutor executor = new MdcTaskExecutor();
        executor.setCorePoolSize(PROCESSORS * 2);
        executor.setMaxPoolSize(PROCESSORS * 4);
        executor.setQueueCapacity(50);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("task-mdc");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }

//    @Bean
//    public FilterRegistrationBean<LogTraceFilter> logTraceFilterFilterRegistrationBean() {
//        FilterRegistrationBean<LogTraceFilter> registration =
//                createFilterRegistrationBean(new LogTraceFilter(), FilterEnums.LOG_TRACE_FILTER.getOrder(), FilterEnums.LOG_TRACE_FILTER.getCode());
//        registration.setDispatcherTypes(DispatcherType.REQUEST);
//        //添加过滤路径
//        registration.addUrlPatterns("/**");
//        /**
//         * todo 由于使用spring security ,将过滤器放在了过滤器链中,避免重复调用将其 enabled 属性设置为 false 来告诉 Spring Boot 不要向容器注册它,非 spring security 环境考虑将其注释掉
//         * 当你把你的 filter 声明为 Spring Bean 时要小心，可以用 @Component 注解它，也可以在配置中把它声明为 Bean，
//         * 因为 Spring Boot 会自动 在嵌入式容器中注册它。这可能会导致 filter 被调用两次，一次由容器调用，一次由 Spring Security 调用，而且顺序不同。
//         */
//        registration.setEnabled(false);
//        return registration;
//    }

    /**
     * 这里预留了口子,默认实现为控制台，而且标注了 @ConditionalOnMissingBean(LogPrinter.class)
     * 如果需要自己实现如:写入到数据库 只要在自己的项目中定义一个  LogPrinter 的bean 即可
     */
    @Bean
    @ConditionalOnMissingBean(LogPrinter.class)
    public LogPrinter logPrinter(LogProperties logProperties) {
        return LogPrinterEnum.obtainPrinter(logProperties.getType());
    }

    @Bean
    public LogEventListener logEventListener(LogPrinter logPrinter) {
        return new LogEventListener(logPrinter);
    }

    @Bean
    public LogAop logAop(ApplicationEventPublisher eventPublisher) {
        return new LogAop(eventPublisher);
    }
}
